﻿
Imports System.IO
Imports xmlctrl
Imports xhtmlctrl
Imports webctrl

Public Class pagination
    Inherits container

    Public Delegate Function generatelinkDelegate(ByVal first As Int64) As String
    Public Delegate Function generatelinkDelegate2(ByVal first As Int64) As a
    Public Delegate Function generatelinktextDelegate(ByVal page As Int64) As String

    Public Shared Function defaultGeneratelinktext(ByVal page As Int64) As String
        Return Convert.ToString(page)
    End Function

    Public Const defaultCountPerPage As Int16 = 10
    Public Const defaultLinkCount As Int16 = 10

    Public Class datasource
        Public Const defaultPrepageText As String = "Prev"
        Public Const defaultNextpageText As String = "Next"
        Public Const defaultEllipsisText As String = "..."
        'first is current start index
        'count is the overall count
        Public first As Int64
        Public count As Int64
        Public countPerPage As Int64 = defaultCountPerPage
        Public linkgenerator As generatelinkDelegate = Nothing
        Public linkgenerator2 As generatelinkDelegate2 = Nothing
        Public textgenerator As generatelinktextDelegate = AddressOf defaultGeneratelinktext
        Public linkcount As Int64 = defaultLinkCount
        Public prepageText As String = defaultPrepageText
        Public nextpageText As String = defaultNextpageText
        Public ellipsisText As String = defaultEllipsisText
        Public page As xhtmlpage = Nothing
        Public mouseonColor As color = pagination.mouseonColor
    End Class

    Public Const paginationItemClassName As String = "wc_pgi"
    Public Const prevnextClassName As String = "wc_pgpn"
    Public Const ellipsisClassName As String = "wc_pges"
    Public Const className As String = "wc_pg"
    Public Shared ReadOnly mouseonColor = New color("E0E0E0")

    Private Sub colorfulInvoke(ByVal ds As datasource, ByVal ctrl As xhtmlControl)
        assert(Not ds Is Nothing, "ds is nothing.")
        assert(Not ctrl Is Nothing, "ctrl is nothing.")

        Dim inlineScript As inlineScript = Nothing
        If Not ds.page Is Nothing Then
            inlineScript = ds.page.inlineScript()
        End If
        colorfulControl.invoke(inlineScript, ctrl, _
                               mouseonColor:=ifoper(ds.mouseonColor Is Nothing, mouseonColor, ds.mouseonColor))
    End Sub

    Public Sub setData(ByVal ds As datasource)
        assert(Not ds Is Nothing, "ds is nothing.")
        assert(Not ds.linkgenerator Is Nothing OrElse Not ds.linkgenerator2 Is Nothing, _
               "ds.linkgenerator and ds.linkgenerator2 are all nothing.")
        assert(Not ds.textgenerator Is Nothing, "ds.textgenerator is nothing.")
        assert(ds.first <= ds.count, "ds.first > ds.count")

        Dim wrap As div = Nothing
        wrap = New div()
        wrap.class = className
        addchild(wrap)

        Dim first As Int64
        If ds.first > 0 Then
            'a prev link
            Dim a As a = Nothing
            first = ds.first - ds.countPerPage
            If first < 0 Then
                first = 0
            End If
            If ds.linkgenerator Is Nothing Then
                a = ds.linkgenerator2(first)
            Else
                a = New a()
                a.href = ds.linkgenerator(first)
            End If
            a.class = prevnextClassName
            a.text = ds.prepageText
            colorfulInvoke(ds, a)
            wrap.addchild(a)
        End If

        first = ds.first - (ds.linkcount >> 1) * ds.countPerPage
        While first + ds.linkcount <= 0
            first += ds.countPerPage
        End While
        Dim i As Int64
        Dim j As Int64
        i = first
        j = 0
        Dim paginationBase As Int64
        'first is 0-based, so 10\ds.countPerPage = 1, but it's the 11st result, should be in 2nd page
        paginationBase = ifoper(first <= 0, 0, (first + 1) \ ds.countPerPage) + 1
        While i < ds.count AndAlso j < ds.linkcount
            Dim this As Int64
            this = i
            If this < 0 Then
                this = 0
            End If
            Dim ctrl As xhtmlControl = Nothing
            If this = ds.first Then
                ctrl = New label()
            Else
                If ds.linkgenerator Is Nothing Then
                    ctrl = ds.linkgenerator2(this)
                Else
                    ctrl = New a()
                    ctrl.href = ds.linkgenerator(this)
                End If
                colorfulInvoke(ds, ctrl)
            End If
            ctrl.class = paginationItemClassName
            ctrl.text = ds.textgenerator(paginationBase + j)
            wrap.addchild(ctrl)

            i += ds.countPerPage
            j += 1
        End While

        If i < ds.count - ds.countPerPage Then
            'add a ...
            Dim label As label = Nothing
            label = New label()
            label.class = ellipsisClassName
            label.text = ds.ellipsisText
            wrap.addchild(label)
        End If

        If ds.count - ds.first > ds.countPerPage Then
            'a next link
            Dim a As a = Nothing
            first = ds.first + ds.countPerPage
            If first >= ds.count Then
                first = ds.count - 1
            End If
            If first < 0 Then
                first = 0
            End If
            If ds.linkgenerator Is Nothing Then
                a = ds.linkgenerator2(first)
            Else
                a = New a()
                a.href = ds.linkgenerator(first)
            End If
            a.class = prevnextClassName
            a.text = ds.nextpageText
            colorfulInvoke(ds, a)
            wrap.addchild(a)
        End If
    End Sub

    Public Sub New(ByVal ds As datasource, Optional ByVal buff As Stream = Nothing)
        Me.New(buff)
        setData(ds)
    End Sub

    Public Sub New(Optional ByVal buff As Stream = Nothing)
        MyBase.New(buff)
    End Sub
End Class
